import random

from django import forms
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from django_redis import get_redis_connection
from utils.encrypt import md5
from utils import tencent
from web import models


class LoginForm(forms.Form):
    role = forms.ChoiceField(
        required=True,
        label='角色',
        choices=(("1", "管理员"), ("2", "客户")),
        widget=forms.Select(attrs={"class": "form-control"}))

    username = forms.CharField(
        label='用户名',
        required=True,
        widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "用户名"})
    )

    password = forms.CharField(
        label='密码',
        min_length=4,
        max_length=15,
        validators=[RegexValidator(r'^[A-Za-z0-9]{3,15}$', '密码必须是数字或字母')],  # 正则
        required=True,
        widget=forms.PasswordInput(attrs={"class": "form-control", "placeholder": "密码"})
    )

    def clean_username(self):
        user = self.cleaned_data['username']
        if len(user) < 3:
            from django.core.exceptions import ValidationError
            raise ValidationError('用户名格式错误(长度需大于3)')
        return user

    def clean_password(self):
        return md5(self.cleaned_data['password'])

    # def clean(self):
        # 1. 对所有值进行校验,无论前面的字段校验成功与否

        # from django.core.exceptions import ValidationError
        # print(self.cleaned_data)
        # raise ValidationError("整体错误")


class SmsLoginForm(forms.Form):
    role = forms.ChoiceField(
        label="角色",
        required=True,
        choices=(("1", "管理员"), ("1", "客户")),
        widget=forms.Select(attrs={"class": "form-control"})
    )

    mobile = forms.CharField(
        label="手机号",
        validators=[RegexValidator(r'^1[358]\d{9}$', '手机号格式错误'), ],
        widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "手机号"})
    )

    code = forms.CharField(
        label="短信验证码",
        validators=[RegexValidator(r'^[0-9]{4}$', '验证码格式错误'), ],
        widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "短信验证码"})
    )

    # 此处可以不做在这里面
    # def clean_mobile(self):
    #     role = self.cleaned_data.get('role')
    #     mobile = self.cleaned_data['mobile']
    #     if not role:
    #         return mobile
    #
    #     if role == "1":
    #         user_object = models.Administrator.objects.filter(active=1, mobile=mobile).first()
    #     else:
    #         user_object = models.Customer.objects.filter(active=1, mobile=mobile).first()
    #     if not user_object:
    #         raise ValidationError("手机号不存在")
    #
    #     return mobile


    def clean_code(self):
        mobile = self.cleaned_data.get('mobile')
        code = self.cleaned_data['code']
        if not mobile:
            return code

        conn = get_redis_connection("default")
        cache_code = conn.get(mobile)
        if not cache_code:
            raise ValidationError("短信验证码未发送或失效")

        if code != cache_code:
            raise ValidationError("短信验证码不匹配")
        return code


class MobileForm(forms.Form):
    role = forms.ChoiceField(
        required=True,
        label='角色',
        choices=(("1", "管理员"), ("2", "客户")),
        widget=forms.Select(attrs={"class": "form-control"}))

    mobile = forms.CharField(
        label="手机号",
        required=True,
        validators=[RegexValidator(r'^1[358]\d{9}$', '手机号格式错误')]
    )

    def clean_mobile(self):
        role = self.cleaned_data.get('role')
        mobile = self.cleaned_data['mobile']

        if role == "1":
            exists = models.Administrator.objects.filter(active=1, mobile=mobile).exists()
        else:
            exists = models.Customer.objects.filter(active=1, obile=mobile).exists()
        if not exists:
            raise ValidationError("手机号不存在(钩子)")

        sms_code = str(random.randint(1000, 9999))
        is_success = tencent.send_sms(mobile, sms_code)
        if not is_success:
            raise ValidationError("短信发送失败(钩子)")

        # 将手机和验证码保存(以便于下次校验） redis->超时时间
        conn = get_redis_connection('default')
        conn.set(mobile, sms_code, ex=60)

        return mobile
